/**
 * 自定义class promise
 * @class ClassPromise
 *
 */
const PENDING = "pending"; // 等待中
const FULFILLED = "fulfilled"; // 实现
const REJECTED = "rejected"; // 驳回
const FINALLY = "finally"; // 结束

class ClassPromise {
  // 构造方法
  constructor(executor) {
    // 数据初始化
    this.initData();

    // 初始化this指向
    this.initThisPoint();

    // 执行器 resolve 和 reject 方法
    executor(this.resolve, this.reject);
  }

  // 数据初始化
  initData() {
    this.status = PENDING; // 状态
    this.data = undefined; // 成功数据
    this.reason = undefined; // 失败原因
    this.successCallback = []; // 记录成功回调的方法
    this.failCallback = []; // 记录失败的回调方法
    this.finallyCallback = []; // 记录结束的回调方法
  }

  // 初始化this指向当前类
  initThisPoint() {
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
  }

  // resolve 方法 -> fulfilled 实现
  resolve(data) {
    // 因为状只能是pending=> fulfilled/rejected 如果其他状态就返回
    if (this.status !== PENDING) return;
    // 执行之后状态更改为fulfilled
    this.status = FULFILLED;
    // 把成功返回值保存在变量里边
    this.data = data;
    // 判断方法是否存在并且执行成功回调方法
    // this.successCallback && this.successCallback(this.data);
    // 因为存在同一个promise对象多种then的情况 所以要把successCallback改为数组,并且在异步时进行调用
    while (this.successCallback.length) {
      this.successCallback.shift()(this.data);
    }
  }

  // reject 方法 -> rejected 驳回
  reject(err) {
    if (this.status !== PENDING) return;
    this.status = REJECTED;
    this.reason = err; // 存储失败的返回值
    // this.failCallback && this.failCallback(this.reason);
    while (this.failCallback.length) {
      this.failCallback.shift()(this.reason);
    }
  }

  // 成功回调
  then(successCallback, failCallback, finallyCallback) {
    // 判断状态 来调用回调函数
    switch (this.status) {
      case FULFILLED: // 通过
        successCallback(this.data);
        break;
      case REJECTED: // 驳回
        failCallback(this.reason);
        break;
      case FINALLY: // 驳回
        finallyCallback();
        break;
      default:
        // 变量记录当前的回调方法  存在异步的执行顺序
        // MyPromise声明 => then方法的调用 => 异步函数返回值调用resolve/reject方法
        // 把当前回调函数添加到数组中
        this.successCallback.push(successCallback);
        this.failCallback.push(failCallback);
        this.finallyCallback.push(finallyCallback);
        break;
    }
  }
}

// 尝试
let promise = new ClassPromise((resolve, reject) => {
  setTimeout(() => {
    resolve("成功");
  }, 1000);
    // reject("失败");
});
promise.then(
  (val) => {
    console.log(val);
  },
  (reason) => {
    console.log(reason);
  }
);
promise.then(
  (val) => {
    console.log(val);
  },
  (reason) => {
    console.log(reason);
  }
);
